#ifndef IRENDERTARGET_H_INCLUDED
#define IRENDERTARGET_H_INCLUDED

#include "ITexture.h"
#include "Transformation.h"
#include "Vertex.h"

/// Predefinitions
/* The predefined classes that are listed below are required so the IRenderTarget could function.
	All these are, of course, abstract and can be overrided at any time. */
class IInstance;		/// This class will function as holder and modifier of transformation. It will refer to a DATAH (IRenderable or IObject, for example), so it could be used as is
class IObject;			/// This class will function as behavioral holder. It will define behaviour of any game objects, such as trees, people, rabbits, etc. It will have a default IInstance inside, that will represent default transformation. Will have a DATAH to a renderable, for example.
class IRenderable;	/// This class will function as a holder of renderable data. Data that can be drawn on the screen. Will contain collision data for models, geometry, light properties, IEffect, IShader, and whatnot (all as DATAH).
class IEffect;			/// This class will function as rendering state holder and processor.
class IShader;			/// This class will function as a shader holder and/or processor
class IRenderQueue;	/// This class will function as a queue and sorter/queue executor
class CCamera;			/// Self explanatory. A Realization of IInstance3D

enum eCULL_STATE {
	CULL_NONE = 0,
	CULL_BACK,
	CULL_FRONT,
	CULL_ALL
};


/// The Abstract Render Target Interface
/* This nasty class will represent an abstract form of a point-of-view and vision.
	In other words: a render target is a texture that you can draw to. And this class helps you do it with ease.
	It can have:
	- an integrated render queue for sorting and optimization,
	- a default camera for navigating our point of view
	- a camera overrider, so we can always swap cameras or even simple instances, but keep the default one "safe" */
class IRenderTarget : public ITexture {
protected:
	int  	 			m_iDepthFormat;		///< Depth Texture Format. As we control a framebuffer, we have to control it's depth too (if we need it)
	IRenderQueue*	m_RenderQueue;			///< Local render queue. Used for optimization and sorting
	CCamera*			m_pCamera;				///< Integrated camera interface. Created on construction;
	IInstance*		m_pCameraOverrider;	///< Designed to override default camera above. If non zero. Zero by default.

	static const long m_DefaultFlagsRenderTarget = eDBF_VRAM | eDBF_STATIC | eDBF_RENDERTARGET;

public:
	// These functions render using the queue:
	virtual void Enqueue	( IInstance* 	instance, 	IRenderable* model ) = 0;
	virtual void Enqueue	( IInstance* 	instance 	) = 0;
	virtual void Enqueue	( IRenderable* model 		) = 0;
	// These functions render directly:
	virtual void Render	( IInstance* 	instance, 	IRenderable* model ) = 0;
	virtual void Render	( IInstance* 	instance 	) = 0;
	virtual void Render	( IRenderable* model 		) = 0;

	// Gets:
	IInstance*	Camera				( ) const { if(m_pCameraOverrider) return m_pCameraOverrider; return (IInstance*)m_pCamera; }

	// These will clear the render target:
	virtual void Clear				( ) = 0;
	virtual void Clear				( crgba &color ) = 0;
	// This will refresh your screen if the render target is your backbuffer:
	virtual void Present				( handle hwnd ) = 0;
	// This will process the local queue. You can either clear the queue, or keep it for later:
	virtual void Process				( ) = 0;
	virtual void ProcessAndKeep	( ) = 0;
	// This will reset the queue:
	virtual void ResetQueue			( ) = 0;

	// Some helper functions for projecting and unprojecting geometry and points from camera space to world space and vice versa
	virtual vec3r 	Project			( cvec3r &point ) = 0;
	virtual vec3r 	Unproject		( cvec3r &point ) = 0;
	virtual void 	ProjectBatch	( vec3r** destination, cvec3r *points, cui32 count ) = 0;
	virtual void 	UnprojectBatch	( vec3r** destination, cvec3r *points, cui32 count ) = 0;

	// Advanced drawing functions. You can use them on your own, but i'd rather use the Process() routine (if you are using the queue) or the automated Render(...) functions above.
	virtual void SetVertexFormat	( culong &format ) = 0;									// Gives a vertex format to the video adapter, so it can read the vertex buffer you send later.
	virtual void SetStateLighting	( bool flag ) = 0;										// Toggle lighting on/off. If you enable lighting and there are no lights on the scene, you will see everything black. Beware.
	virtual void SetStateCulling	( eCULL_STATE flag ) = 0;								// Switch to different culling methods. Cull fronts or backs of polygons, for example. It is faster :P
	virtual void SetStateDepth		( bool flag ) = 0;										// Switch to different depth methods.
	virtual void SetCamera			( IInstance* cam ) = 0;									// Set the override camera. Use NULL to revert to the default one.
	virtual void SetPerspective	( const sCameraData &data ) = 0;						// Set a perspective projection with the data provided
	virtual void SetOrtho			( cint &width, cint &height ) = 0;					// Set an orthogonal projection with the data provided
	virtual void SetView				( cvec3r &pos, cvec3r &view, cvec3r &up ) = 0; 	// Set the eye position and orientation
	virtual void SetView				( IInstance* camera ) = 0; 							// Set the eye position and orientation
	virtual void SetEffect			( IEffect* eff ) = 0;									// Apply effect
	virtual void SetTransform		( IInstance* instance ) = 0;							// Apply transformation
	virtual void SetShader			( IShader* shader ) = 0;								// Apply shader
	virtual void SetLight			( cint i, IInstance* lightinst, 	const sLightData &lightdata ) = 0;		// Apply light
	virtual void SetFog				( crgba &color, cint mode, creal start, creal end, creal density ) = 0;	// Apply fog

	// Tell the video adapter to prepare for drawing
	virtual void Begin( ) = 0;
	// Simple function to render any vertex data from a float array
	virtual void RenderPrimitiveUserPointer( cuint type, cuint count, handle data, cuint stride ) = 0;
	virtual void BeginPrimitive( VERTEX_PRIMITIVE_TYPE primitive_type ) = 0;
	virtual void RenderVertex( cvec3r &point ) = 0;
	virtual void RenderVertex( cvec3r &point, cvec2r &uv ) = 0;
	virtual void RenderVertex( cvec3r &point, cvec2r &uv, crgba &color ) = 0;
	virtual void RenderVertex( cvec3r &point, crgba &color ) = 0;
	virtual void RenderVertex( cvec3r &point, cvec2r &uv, crgba &color, cvec3r &normal ) = 0;
	virtual void EndPrimitive( ) = 0;
	// Tell the video adapter that we are ready with the drawing and stop it
	virtual void End	( ) = 0;


			   // Constructor & Destructor
			   IRenderTarget( int w, int h, byte* data = NULL, int color_format = eTF_RGB24, int depth_format = eTF_DEPTH24, int flags = eDBF_DEFAULT_SETTINGS )
			   :  ITexture( w, h, data, flags ),
					m_iDepthFormat( depth_format ),
					m_RenderQueue( NULL ),
					m_pCamera( NULL ),
					m_pCameraOverrider( NULL )  { }
	virtual ~IRenderTarget( ) {
				}
};

// Shortcodes
typedef IRenderTarget SURFACE;


#endif // IRENDERTARGET_H_INCLUDED
